import React, {Fragment} from 'react';
import {FormattedMessage, intlShape} from 'react-intl';
import PropTypes from 'prop-types';
import TetherComponent from 'react-tether';
import RootCloseWrapper from 'react-overlays/lib/RootCloseWrapper';
import moment from 'moment-timezone';
import contains from 'dom-helpers/query/contains';
import debounce from 'lodash/debounce';
import uniqueId from 'lodash/uniqueId';
import noop from 'lodash/noop';


import {
    IconButton,
    Row,
    Col,
    TextField,
    Button
} from '@folio/stripes/components';
import Calendar from './CalendarDoublePerfect';
import css from './CalendarPerfect.css';

const defaultParser = (value, timeZone, dateFormat) => {
    if (!value || value === '') {
        return value;
    }

    const offsetRegex = /T[\d.:]+[+-][\d]+$/;
    let inputMoment;
    // if date string contains a utc offset, we can parse it as utc time and convert it to selected timezone.
    if (offsetRegex.test(value)) {
        inputMoment = moment.tz(value, timeZone);
    } else {
        inputMoment = moment.tz(value, dateFormat, timeZone);
    }
    const inputValue = inputMoment.format(dateFormat);
    return inputValue;
};

const propTypes = {
    autoFocus: PropTypes.bool,
    backendDateStandard: PropTypes.string,
    date: PropTypes.object,
    dateFormat: PropTypes.string,
    disabled: PropTypes.bool,
    exclude: PropTypes.func,
    hideOnChoose: PropTypes.bool,
    id: PropTypes.string,
    input: PropTypes.object,
    inputRef: PropTypes.object,
    label: PropTypes.node,
    locale: PropTypes.string,
    meta: PropTypes.object,
    onChange: PropTypes.func,
    onSetDate: PropTypes.func,
    parser: PropTypes.func,
    readOnly: PropTypes.bool,
    required: PropTypes.bool,
    screenReaderMessage: PropTypes.string,
    showCalendar: PropTypes.bool,
    tether: PropTypes.object,
    timeZone: PropTypes.string,
    useFocus: PropTypes.bool,
    value: PropTypes.string,
};

const contextTypes = {
    intl: intlShape
};

const defaultProps = {
    autoFocus: false,
    backendDateStandard: 'ISO8601',
    hideOnChoose: true,
    parser: defaultParser,
    screenReaderMessage: '',
    tether: {
        attachment: 'top center',
        targetAttachment: 'bottom center',
        optimizations: {
            gpu: false,
        },
        constraints: [{
            to: 'window',
            attachment: 'together',
        },
            {
                to: 'scrollParent',
                pin: true,
            },
        ],
    },
    useFocus: true,
};

class DateDoublePerfectChoice extends React.Component {
    static propTypes = propTypes;
    static contextTypes = contextTypes;
    static defaultProps = defaultProps;

    constructor(props, context) {
        super(props);

        this.startPicker = null;
        this.endPicker = null;
        this.container = null;
        this.srSpace = null;
        this.textfield = props.inputRef || React.createRef();
        this.hiddenInput = React.createRef();

        this.dbhideCalendar = debounce(this.hideCalendar, 10);

        const timeZone = props.timeZone || context.intl.timeZone;
        const locale = props.locale || context.intl.locale;
        moment.locale(locale);

        const dateFormat = 'YYYY-MM-DD';

        this.state = {
            dateString: '',
            showCalendar: this.props.showCalendar || false,
            srMessage: '',
            dateFormat,
            timeZone,
            prevValue: '',
            locale,
            timeNumber: [],
            dateNumber: [],
            startLightTime: 'HH',
            startRightTime: 'mm',
            endLightTime: 'HH',
            endRightTime: 'mm',
            dateStartString: 'YYYY-MM-DD',
            dateEndString: 'YYYY-MM-DD',

        };

        if (props.id) {
            this.testId = props.id;
        } else {
            this.testId = uniqueId('dp-');
        }
    }

    /* gDSFP handles instances where the value is transitioning from an empty string
    * to some value.
    */
    static getDerivedStateFromProps(props, state) {
        if (!state.prevValue) {
            const timeZone = props.timeZone || state.timeZone;
            const dateFormat = props.dateFormat || state.dateFormat;

            let inputValue = '';
            if (!props.input && !props.date) {
                inputValue = props.parser(props.value, timeZone, dateFormat, state.locale);
            } else {
                inputValue = props.parser(props.input.value, timeZone, dateFormat, state.locale);
            }
            return {
                dateString: inputValue,
                prevValue: props.input ? props.input.value : props.value,
                hiddenValue: props.input ? props.input.value : '',
            };
        }

        return null;
    }

    componentDidUpdate() {
        const {
            input,
            onChange
        } = this.props;

        const {
            changeType,
        } = this.state;

        if (changeType && changeType !== 'invalid') {
            const baseEvent = {
                stopPropagation: noop,
                preventDefault: noop
            };

            if (input && this.hiddenInput.current) {
                input.onChange(
                    Object.assign({}, baseEvent, {target: this.hiddenInput.current})
                );
            } else if (onChange && this.textfield.current) {
                onChange(
                    Object.assign({}, baseEvent, {target: this.textfield.current})
                );
            }
            this.internalSetState({changeType: undefined});
        }
    }

    textfield = React.createRef();

    handleFieldFocus = () => {
        if (this.props.useFocus && !this.props.disabled) {
            this.showCalendar();
        }
    }

    handleFieldClick = () => {
        if (this.props.useFocus) {
            if (!this.state.showCalendar) {
                this.showCalendar();
            }
        }
    }

    handleRootClose = (e) => {
        // used by <RootCloseWrapper> to determine whether or not it should hide the picker.
        // it should determine that the element that's focused is outside of the DatePerfectChoice's containing div and
        // the calendar widget (this.picker).
        if (!contains(this.container, e.target)) {
            if (!this.DatePerfectChoiceIsFocused()) {
                this.hideCalendar();
            }
        }
    }

    showCalendar = () => {
        const {input} = this.props
        if (!!input.value && input.value.search(" / ") != -1) {
            let value = input.value.split(" / ")

            let timeValue1 = value[0];
            let timeValue2 = value[0];
            let startLightTime = '';
            let startRightTime = '';
            let dateStartString = moment(new Date(timeValue1)).format('YYYY-MM-DD');
            let time = moment(new Date(timeValue2)).format('HH:mm');
            if (!!timeValue1 && !!timeValue2 && !!dateStartString && !!time) {
                let timeStr = time.split(":")
                startLightTime = timeStr[0];
                startRightTime = timeStr[1];

            }


            let timeValue3 = value[1];
            let timeValue4 = value[1];
            let endLightTime = '';
            let endRightTime = '';
            let dateEndString = moment(new Date(timeValue3)).format('YYYY-MM-DD');
            let timeEnd = moment(new Date(timeValue4)).format('HH:mm');
            if (!!timeValue1 && !!timeValue2 && !!dateEndString && !!timeEnd) {
                let timeStr = timeEnd.split(":")
                endLightTime = timeStr[0];
                endRightTime = timeStr[1];

            }
            this.setState({
                dateEndString,
                endLightTime,
                endRightTime,
                dateStartString,
                startLightTime,
                startRightTime,
                showCalendar: true,
            },()=>{
                //light-time-01 right-time-01 light-date-01 right-date-01
                this.selectedTime(`light-date-${startLightTime}`,'startLightTime')
                this.selectedTime(`right-time-${startRightTime}`,'startRightTime')
                this.selectedTime(`light-date-${endLightTime}`,'endLightTime')
                this.selectedTime(`right-time-${endRightTime}`,'endRightTime')
            })
            return false;
        }else
        {
            this.setState({
                showCalendar: true,
            });
        }

    }

    hideCalendar = () => {
        this.setState({
            showCalendar: false,
        });
    }

    toggleCalendar = () => {
        const current = this.state.showCalendar;
        this.setState({
            showCalendar: !current,
        });
    }

    handleKeyDown = (e) => {
        if (this.startPicker) {
            const curDate = this.startPicker.getCursorDate();
            const formattedDate = curDate.format(this.state.dateFormat);
            let dateString;
           switch (e.keyCode) {
                case 40: // down
                    e.preventDefault();
                    dateString = this.startPicker.nextWeek();
                    break;
                case 38: // up
                    e.preventDefault();
                    dateString = this.startPicker.previousWeek();
                    break;
                case 37: // left
                    dateString = this.startPicker.previousDay();
                    break;
                case 39: // right
                    dateString = this.startPicker.nextDay();
                    break;
                case 27: // escape
                    e.preventDefault();
                    this.hideCalendar();
                    break;
                case 34: // pgDn
                    e.preventDefault();
                    if (!this.state.showCalendar) {
                        return;
                    }
                    if (!e.altKey) {
                        dateString = this.startPicker.nextMonth();
                    } else {
                        dateString = this.startPicker.nextYear();
                    }
                    break;
                case 33: // pgUp
                    e.preventDefault();
                    if (!this.state.showCalendar) {
                        return;
                    }
                    if (!e.altKey) {
                        dateString = this.startPicker.previousMonth();
                    } else {
                        dateString = this.startPicker.previousYear();
                    }
                    break;
                case 13: // enter
                    e.preventDefault();
                    if (this.state.showCalendar) {
                        this.handleSetDate(e, curDate, formattedDate);
                    } else {
                        this.showCalendar();
                    }
                    dateString = (
                        <FormattedMessage
                            id="stripes-components.dateSelected"
                            values={{date: formattedDate}}
                        />
                    );
                    break;
                case 9: // tab
                    this.hideCalendar();
                    break;
                default:
            }
            this.informScreenReader(`${dateString}`);
        } else {
            switch (e.keyCode) {
                case 13: // enter
                case 40: // down
                    e.preventDefault();
                    this.showCalendar();
                    break;
                default:
            }
        }
    }

    internalSetState = (state, changeType, callbacks) => {
        this.setState(curState => {
                return Object.assign({}, curState, state, {changeType});
            },
            () => {
                if (callbacks) {
                    callbacks.forEach((cb) => {
                        cb(this.state);
                    });
                }
            });
    }

    handleSetStartDate = (e, date, stringDate) => {

        const isValidDate = moment(stringDate, this.state.dateFormat, true).isValid();

        let standardizedDate;

        if (e.type === 'click' || e.type === 'keydown') {
            e.preventDefault();
            this.textfield.current.focus();

            if (isValidDate) {
                // convert date to ISO 8601 format for backend
                standardizedDate = this.standardizeDate(stringDate);

                // handlers take the value rather than the event...
                this.internalSetState(
                    {
                        dateStartString: stringDate,
                        hiddenValue: standardizedDate,
                        prevValue: stringDate,
                    },
                    'calendar',
                );
            }
        } else if (e.type === 'change') {
            const tempString = e.target.value;
            // be sure that value is parseable as a date in the required format...
            // the boolean parameter suppresses moment's deprecation warning,
            // preventing it from attempting a parse using independable js Date object.
            if (moment(tempString, this.state.dateFormat, true).isValid()) {
                standardizedDate = this.standardizeDate(e.target.value);
                this.internalSetState(
                    {
                        dateStartString: e.target.value,
                        hiddenValue: standardizedDate,
                        prevValue: e.target.value,
                    },
                    'validEntry',
                );
            } else {
                // if it's not a valid date, update field value only so that
                // we can still see what we typed in the field...
                this.internalSetState(
                    {
                        dateStartString: e.target.value,
                        hiddenValue: '',
                    },
                    'invalid'
                );
            }
        }
    }
    handleSetEndDate = (e, date, stringDate) => {

        const isValidDate = moment(stringDate, this.state.dateFormat, true).isValid();

        let standardizedDate;

        if (e.type === 'click' || e.type === 'keydown') {
            e.preventDefault();
            this.textfield.current.focus();

            if (isValidDate) {
                // convert date to ISO 8601 format for backend
                standardizedDate = this.standardizeDate(stringDate);

                // handlers take the value rather than the event...
                this.internalSetState(
                    {
                        dateEndString: stringDate,
                        hiddenValue: standardizedDate,
                        prevValue: stringDate,
                    },
                    'calendar',
                );
            }
        } else if (e.type === 'change') {
            const tempString = e.target.value;
            // be sure that value is parseable as a date in the required format...
            // the boolean parameter suppresses moment's deprecation warning,
            // preventing it from attempting a parse using independable js Date object.
            if (moment(tempString, this.state.dateFormat, true).isValid()) {
                standardizedDate = this.standardizeDate(e.target.value);
                this.internalSetState(
                    {
                        dateEndString: e.target.value,
                        hiddenValue: standardizedDate,
                        prevValue: e.target.value,
                    },
                    'validEntry',
                );
            } else {
                // if it's not a valid date, update field value only so that
                // we can still see what we typed in the field...
                this.internalSetState(
                    {
                        dateEndString: e.target.value,
                        hiddenValue: '',
                    },
                    'invalid'
                );
            }
        }
    }

    handleFieldChange = (e) => {
        if (e.target.value === '') {
            this.clearDate();
        } else {
            this.handleSetDate(e, e.target.value, e.target.value);
        }
    }

    clearDate = () => {
        this.internalSetState(
            {
                dateString: '',
                hiddenValue: '',
            },
            'clear',
        );
    }

    cleanForScreenReader(str) {
        return str.replace(/Y/g, 'Y ');
    }

    informScreenReader(str) {
        this.setState({srMessage: str});
    }

    DatePerfectChoiceIsFocused() {
        if (contains(this.container, document.activeElement) &&
            document.activeElement !== document.body) {
            if (this.startPicker) {
                return (contains(this.startPicker.getDOMContainer(), document.activeElement));
            }
            return true;
        }
        return false;
    }

    hideOnBlur = (e) => {
        const {
            input
        } = this.props;

        if (this.DatePerfectChoiceIsFocused()) {
            if (input && input.onBlur) {
                input.onBlur(e);
            }
            this.hideCalendar();
            this.setState({srMessage: ''});
        }
    }

    standardizeDate(date) {
        const parsed = moment.tz(date, this.state.dateFormat, this.state.timeZone).isValid;

        if (parsed) {
            return date;
        }
        date = moment(new Date()).format('YYYY-MM-DD');
        return date;
    }



    renderCalendar() {
        const {startExclude, input} = this.props;

        return (

            <Calendar
                onSetDate={this.handleSetStartDate}
                selectedDate={this.state.dateStartString}
                dateFormat={this.state.dateFormat}
                ref={(ref) => {
                    this.startPicker = ref;
                }}
                onKeyDown={this.handleKeyDown}
                onBlur={this.hideCalendar}
                locale={this.state.locale}
                exclude={startExclude}
                id={this.testId}

            />

        );



    }

    renderEndCalendar() {

        const {endExclude, input} = this.props;

        return (
            <Calendar
                onSetDate={this.handleSetEndDate}
                selectedDate={this.state.dateEndString}
                dateFormat={this.state.dateFormat}
                ref={(ref) => {
                    this.endPicker = ref;
                }}
                onKeyDown={this.handleKeyDown}
                onBlur={this.hideCalendar}
                locale={this.state.locale}
                exclude={endExclude}
                id={this.testId}
            />

        );



    }

    renderEndElement() {
        return (
            <Fragment>
                {this.state.dateString !== '' && (
                    <FormattedMessage id="stripes-components.clearFieldValue">
                        {ariaLabel => (
                            <IconButton
                                data-test-clear
                                key="clearButton"
                                onClick={this.clearDate}
                                aria-label={ariaLabel}
                                id={`DatePerfectChoice-clear-button-${this.testId}`}
                                tabIndex="-1"
                                icon="times-circle-solid"
                            />
                        )}
                    </FormattedMessage>
                )}
                <FormattedMessage id="ui-party.stripes-components.showOrHideDatePerfectChoice">
                    {ariaLabel => (
                        <IconButton
                            data-test-calendar-button
                            onClick={this.toggleCalendar}
                            onKeyDown={this.handleKeyDown}
                            aria-label={ariaLabel}
                            id={`DatePerfectChoice-toggle-calendar-button-${this.testId}`}
                            tabIndex="-1"
                            icon="calendar"
                        />
                    )}
                </FormattedMessage>
            </Fragment>
        );
    }

    renderInput() {
        const {
            input,
            screenReaderMessage,
            label,
            readOnly,
            required,
            disabled,
            autoFocus,
            placeholder
        } = this.props;

        const {
            dateFormat,
        } = this.state;

        const screenReaderFormat = this.cleanForScreenReader(this.state.dateFormat);

        let ariaLabel;
        if (readOnly || disabled) {
            ariaLabel = `${label}`;
        } else {
            ariaLabel = (
                <FormattedMessage
                    id="stripes-components.screenReaderLabel"
                    values={{label, screenReaderFormat, screenReaderMessage}}
                />
            );
        }

        let textfieldProps = {
            label,
            readOnly,
            disabled,
            required,
            autoFocus,
            'id': this.testId,
            'inputRef': this.textfield,
            'onChange': this.handleSetDate,
            'value': this.state.dateString,
            'aria-label': ariaLabel,
            'placeholder': placeholder || `${dateFormat}`,
            'onBlur': this.hideOnBlur,
            'hasClearIcon': false,
            'autoComplete': 'off',
        };

        if (!readOnly && !disabled) {
            textfieldProps = {
                ...textfieldProps,
                endControl: this.renderEndElement(),
                onKeyDown: this.handleKeyDown,
                onClick: this.handleFieldClick,
                onFocus: this.handleFieldFocus
            };
        }

        if (this.props.input && this.props.meta) {
            textfieldProps = {
                ...textfieldProps,
                meta: this.props.meta,
                input: {...input, value: this.state.dateString},
                onChange: this.handleFieldChange,
                onBlur: (e) => {
                    input.onBlur();
                    e.preventDefault();
                }
            };
        }

        return <TextField {...textfieldProps} />;
    }

    dateNumber = (str, classId) => {
        let num = []

        for (let i = 1; i < 24; i++) {
            if (i < 10) {
                num.push(<div key={`${str}-date-0${i}`} id={`${str}-date-0${i}`} onClick={(e) => {
                    this.selectTime(e, classId)
                }}>{`0${i}`}</div>)
            } else {
                num.push(<div key={`${str}-date-${i}`} id={`${str}-date-${i}`} onClick={(e) => {
                    this.selectTime(e, classId)
                }}>{i}</div>)
            }

        }
        return num;
    }//background-color: #1e88e561
    timeNumber = (str, classId) => {
        let num = []

        for (let i = 0; i < 60; i++) {
            if (i < 10) {
                num.push(<div key={`${str}-time-0${i}`} id={`${str}-time-0${i}`} onClick={(e) => {
                    this.selectTime(e, classId)
                }}>{`0${i}`}</div>)
            } else {
                num.push(<div key={`${str}-time-${i}`} id={`${str}-time-${i}`} onClick={(e) => {
                    this.selectTime(e, classId)
                }}>{i}</div>)
            }
        }//light-time-01 right-time-01 light-date-01 right-date-01
        return num;
    }
    selectTime = (e, classId) => {
        let divSelect = document.getElementById(classId).children
        for (let i = 0; i < divSelect.length; i++) {
            divSelect[i].removeAttribute('style');
        }
        e.target.style.backgroundColor = '#106c9e';
        e.target.style.color = '#fff';
        e.target.style.border=' 2px solid #666'
        let value = e.target.innerHTML
        let data = {}
        data[classId] = value

        this.setState(data)
    }
    selectedTime = (targetId, classId) => {

        let divSelect = document.getElementById(classId).children
        if ( !!divSelect)
        {
            let target= null;
            for (let i = 0; i < divSelect.length; i++) {
                divSelect[i].removeAttribute('style');
                let id =  divSelect[i].id
                if (targetId === id)
                {
                    target=divSelect[i]
                    target.style.backgroundColor = '#106c9e';
                    target.style.color = '#fff';
                    target.style.border= '2px solid #666'
                }
            }

        }


    }
    saveInput = () => {

        let str = `${this.state.dateStartString} ${this.state.startLightTime}:${this.state.startRightTime} / ${this.state.dateEndString} ${this.state.endLightTime}:${this.state.endRightTime}`

        let result = /[a-zA-Z]+/.test(str)
        if (!result){
        this.props.input.onBlur(str)
        this.setState({
            dateString: str,
            prevValue: str,
            hiddenValue: str,
            startLightTime: 'HH',
            startRightTime: 'mm',
            endLightTime: 'HH',
            endRightTime: 'mm',
            dateStartString: 'YYYY-MM-DD',
            dateEndString: 'YYYY-MM-DD',
        }, () => {
            this.hideCalendar();
        })
        }
    }

    render() {
        const propStyle = {
            "height": "410px",
            "width": "930px",
            "boxShadow": "0 4px 32px rgba(0, 0, 0, 0.175)",
            "borderRadius": "8px",
            "backgroundColor": "white",
            "border": "1px solid #bcbcbc",
            "transform": 'scale(0.7)'
        }
        const divStyle = {"height": "100%", "border": "1px solid rgb(188, 188, 188)"}
        const heightStyle = {height: '100%'}
        const lightStyle = {
            "float": "left",
            "width": "60px",
            "height": "100%",
            "overflow": "auto",
            "borderWidth": "0 1px 0 0",
            "borderStyle": "solid",
            "borderColor": "#0000001c"
        }
        const rightStyle = {
            "float": "left",
            "width": "57px",
            "height": "100%",
            "overflow": "auto",
            "borderWidth": "0 1px 0 0",
            "borderStyle": "solid",
            "borderColor": "#0000001c"
        }
        const showStyle = {
            "height": "100%",
            "textAlign": "center",
            "padding": "15px",
            "fontSize": "16px",
            "fontWeight": "800"
        }
        const buttonDivStyle = {"width": "80%", "height": "40px", "margin": "0 auto"}

        return (
            <TetherComponent {...defaultProps.tether} {...this.props.tether}>
                <div style={{position: 'relative', width: '100%'}} ref={(ref) => {
                    this.container = ref;
                }}>
                    <div
                        aria-live="assertive"
                        aria-relevant="additions"
                        className={css.srOnly}
                        ref={(ref) => {
                            this.srSpace = ref;
                        }}
                    >
                        <div>{this.state.srMessage}</div>
                    </div>
                    {this.renderInput()}
                    <input type="hidden" hidden value={this.state.hiddenValue} ref={this.hiddenInput}/>
                </div>
                {
                    this.state.showCalendar &&
                    <RootCloseWrapper>
                        <div style={propStyle}>
                            <div style={{height: '40px'}}>
                                <div style={showStyle}>{
                                    `${this.state.dateStartString} ${this.state.startLightTime}:${this.state.startRightTime} / ${this.state.dateEndString}  ${this.state.endLightTime}:${this.state.endRightTime}`
                                }</div>

                            </div>
                            <Row center={"xs"} style={{height: '310px'}}>

                                <Col xs={4} style={heightStyle}>
                                    <div style={divStyle}>
                                        {this.renderCalendar()}
                                    </div>
                                </Col>
                                <Col style={heightStyle}>
                                    <div style={divStyle}>
                                        <div style={lightStyle} class="timeSelect"
                                             id={"startLightTime"}>{this.dateNumber('light', 'startLightTime')}</div>
                                        <div style={rightStyle} class="timeSelect"
                                             id={"startRightTime"}>{this.timeNumber('right', 'startRightTime')}</div>
                                    </div>
                                </Col>
                                <Col xs={4} style={heightStyle}>
                                    <div style={divStyle}>
                                        {this.renderEndCalendar()}
                                    </div>
                                </Col>
                                <Col style={heightStyle}>
                                    <div style={divStyle}>
                                        <div style={lightStyle} class="timeSelect"
                                             id={"endLightTime"}>{this.dateNumber('light', 'endLightTime')}</div>
                                        <div style={rightStyle} class="timeSelect"
                                             id={"endRightTime"}>{this.timeNumber('right', 'endRightTime')}</div>
                                    </div>
                                </Col>
                            </Row>
                            <div style={buttonDivStyle}>
                                <Button fullWidth style={{marginTop: '15px'}} onClick={() => {
                                    this.saveInput()
                                }}> 确 定</Button>
                            </div>
                        </div>
                    </RootCloseWrapper>
                }
            </TetherComponent>
        );
    }
}

export default DateDoublePerfectChoice;
